Skip to content

Fix ZIP64 handling for Outlook OLM and other low-version producers#378

Open
xgimpx wants to merge 1 commit intoweichsel:developmentfrom
xgimpx:fix/zip64-outlook-olm-compatibility
Open

Fix ZIP64 handling for Outlook OLM and other low-version producers#378
xgimpx wants to merge 1 commit intoweichsel:developmentfrom
xgimpx:fix/zip64-outlook-olm-compatibility

Conversation

@xgimpx
Copy link

@xgimpx xgimpx commented Feb 22, 2026

Summary

Two issues prevent ZIPFoundation from reading ZIP64 archives produced by Microsoft Outlook (OLM export) and potentially other ZIP producers that use ZIP64 structures with non-standard version fields:

Bug 1: ZIP64 EOCD version check too strict

ZIP64EndOfCentralDirectoryRecord.init rejects records where versionNeededToExtract < 45 (v4.5). Outlook writes ZIP64 structures with versionNeededToExtract = 10 (v1.0) because it only uses store compression. The fallback to the standard EOCD — which has all fields set to 0xFFFF/0xFFFFFFFF (ZIP64 overflow indicators) — makes the central directory offset point to 4 GB, past end of file, resulting in 0 entries.

Fix: Removed the version guard. The ZIP64 EOCD Record signature (0x06064B50) is already validated, which is sufficient to identify the record.

Bug 2: effectiveXXX properties reject zero values

effectiveCompressedSize, effectiveUncompressedSize, and effectiveRelativeOffsetOfLocalHeader use > 0 to decide whether to use the ZIP64 extended information value. This incorrectly treats 0 as "not present" instead of as a legitimate value:

  • The first entry in any archive has relativeOffsetOfLocalHeader = 0
  • Empty files and directories have compressedSize = 0 and uncompressedSize = 0

When the ZIP64 value is rejected, the code falls back to the 32-bit field which contains 0xFFFFFFFF → invalid offset → iteration fails on the first entry → 0 entries.

Fix: Changed the condition from value > 0 to self.field == .max, which correctly checks whether the 32-bit field contains the ZIP64 overflow indicator and the ZIP64 value should be used.

Diagnostic evidence

Tested with a real 41 MB Outlook OLM file (387 entries, 4 email accounts):

Tool Entries found
zipinfo 387
Python zipfile 387
ZIPFoundation 0.9.20 (before fix) 0
ZIPFoundation (after fix) 387

OLM file structure:

EOCD:        entries=0xFFFF, cd_size=0xFFFFFFFF, cd_offset=0xFFFFFFFF
ZIP64 EOCD:  versionNeeded=10, entries=387, cd_offset=41273746
First CD entry: relativeOffsetOfLocalHeader=0xFFFFFFFF, ZIP64 extra: offset=0

Changes

  • Archive+ZIP64.swift: Removed versionNeededToExtract >= 45 guard
  • Entry.swift: Changed value > 0 to self.field == .max in all three effectiveXXX properties
  • ZIPFoundationArchiveTests+ZIP64.swift: Updated test to expect acceptance of low-version ZIP64 records

Test plan

  • All 126 existing ZIPFoundation tests pass
  • Tested with real Outlook OLM file (ZIP64 with version 1.0)
  • First entry at offset 0 is correctly read
  • All 387 entries enumerated successfully

🤖 Generated with Claude Code

…ffset 0

Two issues prevented reading ZIP64 archives produced by Microsoft Outlook
(OLM export) and potentially other producers:

1. ZIP64EndOfCentralDirectoryRecord.init rejected records where
   versionNeededToExtract < 4.5. Outlook writes ZIP64 structures with
   version 1.0 (since it only uses store compression). The ZIP64 EOCD
   signature is already validated, which is sufficient to identify the
   record. Removed the version guard.

2. effectiveCompressedSize, effectiveUncompressedSize, and
   effectiveRelativeOffsetOfLocalHeader used `> 0` to decide whether
   to use the ZIP64 value. This incorrectly rejected legitimate zero
   values — e.g. the first entry in an archive has offset 0, and empty
   files/directories have size 0. Changed to check whether the 32-bit
   field equals `.max` (the ZIP64 overflow indicator) instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant